package com.simon.nearbyfootball.misc;

import java.util.Date;

import android.R.integer;
import android.app.ActivityManager;
import android.content.Context;
import android.util.Log;

public class Logger {
	private static final Logger m_log = Logger.getLogger();
	private static final int source_index = 4;
	private static final int funcition_entry = 1;
	private static final int funcition_leave = 2;
	private static final int control_tag_none = -1;

	public static enum LogLvl {
		FATAL(0, "FATAL"), ERROR(1, "ERROR"), WARN(2, "WARNING"), INFO(3,
				"INFO"), DEBUG(4, "DEBUG"), TRACE(5, "TRACE"), FINE_TRACE(6,
				"FTRACE"), FUNCTION_TRACE(7, "FUNTRACE"), STACK_TRACE(8,
				"STACKTRACE");

		LogLvl(int lvl, String label) {
			this.lvl = lvl;
			this.label = label;
		}

		public int lvl;
		public String label;
	}

	private volatile static int LOG_LVL = LogLvl.FINE_TRACE.lvl;
	private static final String DATE_FORMAT = "z,yyyy-MM-dd HH:mm:ss.SSS";
	private static final ThreadLocal<EnhancementDateFormat> sdf = new ThreadLocal<EnhancementDateFormat>() {
		@Override
		protected EnhancementDateFormat initialValue() {
			return new EnhancementDateFormat(DATE_FORMAT);
		}
	};

	private String tag;
	@SuppressWarnings("rawtypes")
	private Class clazz;

	private Logger() {
		super();
		this.clazz = clazz;
		this.tag = "[NearbyFootball]";
	}

	public static Logger getLogger() {
		return new Logger();
	}

	public static void setLogLevel(int log_lvl) {
		LOG_LVL = log_lvl;
	}

	public static boolean isFatal() {
		return LOG_LVL >= LogLvl.FATAL.lvl;
	}

	public static boolean isError() {
		return LOG_LVL >= LogLvl.ERROR.lvl;
	}

	public static boolean isWarn() {
		return LOG_LVL >= LogLvl.WARN.lvl;
	}

	public static boolean isInfo() {
		return LOG_LVL >= LogLvl.INFO.lvl;
	}

	public static boolean isDebug() {
		return LOG_LVL >= LogLvl.DEBUG.lvl;
	}

	public static boolean isTrace() {
		return LOG_LVL >= LogLvl.TRACE.lvl;
	}

	public static boolean isFineTrace() {
		return LOG_LVL >= LogLvl.FINE_TRACE.lvl;
	}

	public static boolean isFuctionTrace() {
		return LOG_LVL >= LogLvl.FUNCTION_TRACE.lvl;
	}

	public static boolean isStackTrace() {
		return LOG_LVL >= LogLvl.STACK_TRACE.lvl;
	}

	static public void fatal(String message, Exception ex) {
		Log.e(m_log.tag,
				m_log.toLogMsg(message, LogLvl.FATAL, control_tag_none), ex);
	}

	static public void error(String message, Throwable throwable) {
		Log.e(m_log.tag,
				m_log.toLogMsg(message, LogLvl.ERROR, control_tag_none),
				throwable);
	}

	static public void error(Throwable e) {
		Log.e(m_log.tag,
				m_log.toLogMsg(e.getMessage(), LogLvl.ERROR, control_tag_none),
				e);
	}

	static public void error(String message) {
		Log.e(m_log.tag,
				m_log.toLogMsg(message, LogLvl.ERROR, control_tag_none));
	}

	static public void warn(String message) {
		Log.w(m_log.tag, m_log.toLogMsg(message, LogLvl.WARN, control_tag_none));
	}

	static public void warn(String message, Throwable e) {
		Log.w(m_log.tag,
				m_log.toLogMsg(message, LogLvl.WARN, control_tag_none), e);
	}

	static public void info(String message) {
		Log.i(m_log.tag, m_log.toLogMsg(message, LogLvl.INFO, control_tag_none));
	}

	static public void info(String message, Throwable e) {
		Log.i(m_log.tag,
				m_log.toLogMsg(message, LogLvl.INFO, control_tag_none), e);
	}

	static public void debug(String message) {
		Log.d(m_log.tag,
				m_log.toLogMsg(message, LogLvl.DEBUG, control_tag_none));
	}

	static public void debug(String message, Exception e) {
		Log.d(m_log.tag,
				m_log.toLogMsg(message, LogLvl.DEBUG, control_tag_none), e);
	}

	static public void trace(String message, Exception e) {
		Log.v(m_log.tag,
				m_log.toLogMsg(message, LogLvl.TRACE, control_tag_none), e);
	}

	static public void trace(String message) {
		Log.v(m_log.tag,
				m_log.toLogMsg(message, LogLvl.TRACE, control_tag_none));
	}

	static public void finetrace(String message) {
		Log.v(m_log.tag,
				m_log.toLogMsg(message, LogLvl.FINE_TRACE, control_tag_none));
	}

	static public void funtcionEntry() {
		if(!isFuctionTrace()){
			return;
		}
		Log.v(m_log.tag, m_log.toLogMsg("function entry",
				LogLvl.FUNCTION_TRACE, funcition_entry));
	}

	static public void funtcionExit() {
		if(!isFuctionTrace()){
			return;
		}
		Log.v(m_log.tag, m_log.toLogMsg("function leave",
				LogLvl.FUNCTION_TRACE, funcition_leave));
	}

	static public void dumpStackTrace() {
		if(!isStackTrace()){
			return;
		}
		StackTraceElement[] stackArray = Thread.currentThread().getStackTrace();
		int index = 1;
		StringBuilder sb = new StringBuilder();

		for (StackTraceElement element : stackArray) {
			if (index < source_index) {
				index++;
				continue;
			}
			sb.append(" at " + element.toString() + ";\n");
		}
		Log.v(m_log.tag, m_log.toLogMsg("statck trace:" + sb.toString(),
				LogLvl.FUNCTION_TRACE, control_tag_none));
	}

	private String toLogMsg(String message, LogLvl lvl, int control_tag) {
		StringBuilder sb = new StringBuilder();
		int line = -1;
		String function = "";
		String file = "";
		String className = "";

		if (Thread.currentThread().getStackTrace().length > source_index) {
			StackTraceElement element = Thread.currentThread().getStackTrace()[source_index];
			line = element.getLineNumber();
			function = element.getMethodName();
			file = element.getFileName();
			className = file.split("\\.")[0];
		}

		if (control_tag == funcition_entry) {
			message = String.format("%s.%s() at %s:%d enter", className,
					function, file, line);
		} else if (control_tag == funcition_leave) {
			message = String.format("%s.%s() at %s:%d exit", className,
					function, file, line);
		}

		sb.append(android.os.Process.myPid());
		sb.append(",").append(Thread.currentThread().getId());
		sb.append(",").append(lvl.label);
		sb.append(",").append(file + "," + line + "," + function + "()");
		sb.append(",").append(sdf.get().enhFormat(new Date()));
		sb.append(",").append(message);
		return sb.toString();
	}

}
